<?php

namespace App\Http\Controllers;

use App\Services\OpenAIService;
use App\Services\UserService;
use App\Services\FunctionExecutionService;
use Illuminate\Support\Facades\Log;

class AssistantController extends Controller
{
    protected $openAIService;
    protected $userService;
    protected $functionExecutionService;

    public function __construct(OpenAIService $openAIService, UserService $userService, FunctionExecutionService $functionExecutionService)
    {
        $this->openAIService = $openAIService;
        $this->userService = $userService;
        $this->functionExecutionService = $functionExecutionService;
    }

    public function generateAssistantsResponse(string $userMessage, int $userId = null)
    {
        $assistantId = 'asst_pL21UlurObNwTZMSUgFYnbIc';

        $threadId = $this->userService->getOrCreateThread($userId);

        try {
            $message = $this->openAIService->submitMessage($threadId, $userMessage);
        } catch (\OpenAI\Exceptions\ErrorException $e) {
            if (preg_match('/run_[a-zA-Z0-9]+ is active/', $e->getMessage(), $matches)) {
                preg_match('/run_[a-zA-Z0-9]+/', $matches[0], $runMatches);
                $activeRunId = $runMatches[0];

                $this->openAIService->cancelRun($threadId, $activeRunId);

                $message = $this->openAIService->submitMessage($threadId, $userMessage);
            } else {
                return response()->json(['error' => 'Error adding message to thread'], 500);
            }
        }

        $run = $this->openAIService->createRun($threadId, ['assistant_id' => $assistantId]);
        $run = $this->openAIService->waitOnRun($run, $threadId);

        if ($run->status == 'completed') {
            $messages = $this->openAIService->getMessages($run->threadId, 'asc', $message->id);
            $messagesData = $messages->data;

            if (!empty($messagesData)) {
                $assistantResponseMessage = '';

                foreach ($messagesData as $msg) {
                    $assistantResponseMessage .= $msg->content[0]->text->value . "\n\n";
                }

                $assistantResponseMessage = rtrim($assistantResponseMessage);

                return response()->json([
                    "assistant_response" => $assistantResponseMessage,
                ]);
            } else {
                Log::error('Assistant did not respond.');
                return response()->json(['error' => 'Something went wrong; assistant didn\'t respond'], 500);
            }
        } elseif ($run->status == 'requires_action') {
            $toolCalls = $run->requiredAction->submitToolOutputs->toolCalls;

            $results = [];
            foreach ($toolCalls as $toolCall) {
                $funcName = $toolCall['function']['name'];
                $funcData = json_decode($toolCall['function']['arguments'], true);
                try {
                    $result = $this->functionExecutionService->executeFunction($funcName, $funcData);
                    $results[] = ['function' => $funcName, 'result' => $result];
                } catch (\Exception $e) {
                    return response()->json(['error' => $e->getMessage()], 500);
                }
            }

            // Отправка результатов обратно в OpenAI для завершения выполнения
            try {
                $this->openAIService->submitToolOutputs($threadId, $run->id, $results);
                return response()->json([
                    "assistant_response" => 'Требуемые действия выполнены и отправлены обратно в OpenAI',
                    "results" => $results,
                ]);
            } catch (\Exception $e) {
                return response()->json(['error' => 'Error submitting tool outputs: ' . $e->getMessage()], 500);
            }
        } else {
            Log::error('Run was not completed successfully. Status: ' . $run->status);
            return response()->json(['error' => 'Run was not completed successfully', 'status' => $run->status], 500);
        }
    }
}
